package com.example.dependencyscanner.service;

import com.example.dependencyscanner.model.DependencyInfo;
import com.example.dependencyscanner.model.DependencyRisk;
import com.example.dependencyscanner.model.Vulnerability;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 在线漏洞扫描服务 (仅使用OSV.dev作为数据源)
 * 集成OSV.dev API进行漏洞检测，提供高性能、无速率限制的漏洞扫描
 */
@Service
public class OnlineVulnerabilityService {
    
    private static final Logger logger = LoggerFactory.getLogger(OnlineVulnerabilityService.class);
    
    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;
    private final ExecutorService executorService;
    
    @Value("${vulnerability.scan.timeout:30}")
    private int scanTimeout;
    
    @Value("${vulnerability.scan.parallel:true}")
    private boolean enableParallelScan;
    
    public OnlineVulnerabilityService(RestTemplate restTemplate, ObjectMapper objectMapper) {
        this.restTemplate = restTemplate;
        this.objectMapper = objectMapper;
        this.executorService = Executors.newFixedThreadPool(10);
    }

    /**
     * 扫描依赖漏洞
     */
    public List<DependencyRisk> scanDependencies(List<DependencyInfo> dependencies) {
        if (dependencies == null || dependencies.isEmpty()) {
            return new ArrayList<>();
        }
        
        logger.info("开始扫描 {} 个依赖包 (使用OSV.dev)", dependencies.size());
        
        List<DependencyRisk> risks = enableParallelScan ? 
            scanParallel(dependencies) : scanSequential(dependencies);
        
        logger.info("漏洞扫描完成，共发现 {} 个风险", risks.size());
        return risks;
    }
    
    /**
     * 并行扫描
     */
    private List<DependencyRisk> scanParallel(List<DependencyInfo> dependencies) {
        List<CompletableFuture<List<DependencyRisk>>> futures = new ArrayList<>();
        
        for (DependencyInfo dependency : dependencies) {
            CompletableFuture<List<DependencyRisk>> future = CompletableFuture.supplyAsync(
                () -> scanSingleDependency(dependency), executorService
            );
            futures.add(future);
        }
        
        List<DependencyRisk> allRisks = new ArrayList<>();
        for (CompletableFuture<List<DependencyRisk>> future : futures) {
            try {
                List<DependencyRisk> risks = future.get(scanTimeout, TimeUnit.SECONDS);
                allRisks.addAll(risks);
            } catch (Exception e) {
                logger.warn("依赖扫描超时或失败: {}", e.getMessage());
            }
        }
        
        return allRisks;
    }
    
    /**
     * 顺序扫描
     */
    private List<DependencyRisk> scanSequential(List<DependencyInfo> dependencies) {
        List<DependencyRisk> allRisks = new ArrayList<>();
        
        for (DependencyInfo dependency : dependencies) {
            try {
                List<DependencyRisk> risks = scanSingleDependency(dependency);
                allRisks.addAll(risks);
            } catch (Exception e) {
                logger.warn("依赖 {}:{} 扫描失败: {}", 
                           dependency.getGroupId(), dependency.getArtifactId(), e.getMessage());
            }
        }
        
        return allRisks;
    }
    
    /**
     * 扫描单个依赖 (仅使用OSV.dev作为唯一数据源)
     */
    private List<DependencyRisk> scanSingleDependency(DependencyInfo dependency) {
        List<DependencyRisk> risks = new ArrayList<>();
        
        logger.debug("开始扫描依赖: {}:{} (使用OSV.dev)", dependency.getGroupId(), dependency.getArtifactId());
        
        try {
            List<DependencyRisk> osvRisks = scanWithOSV(dependency);
            risks.addAll(osvRisks);
            logger.debug("三方库[{}] OSV.dev 查询完成，发现 {} 个漏洞", dependency.getGroupId() + ":" + dependency.getArtifactId(), osvRisks.size());
        } catch (Exception e) {
            logger.debug("OSV.dev数据库查询失败: {}", e.getMessage());
        }

        // 去重并增强安全版本信息
        List<DependencyRisk> uniqueRisks = removeDuplicates(risks);
        return uniqueRisks;
    }
    
    /**
     * 使用OSV.dev数据库扫描 (优化版)
     */
    private List<DependencyRisk> scanWithOSV(DependencyInfo dependency) {
        List<DependencyRisk> risks = new ArrayList<>();
        
        try {
            String url = "https://api.osv.dev/v1/query";
            
            // 构建请求体 - 使用标准的Maven包名格式
            Map<String, Object> requestBody = new HashMap<>();
            Map<String, String> packageInfo = new HashMap<>();
            packageInfo.put("ecosystem", "Maven");
            packageInfo.put("name", dependency.getGroupId() + ":" + dependency.getArtifactId());
            requestBody.put("package", packageInfo);
            requestBody.put("version", dependency.getVersion());
            
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
            headers.set("User-Agent", "DependencyScanner/1.0");
            
            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
            
            logger.debug("OSV.dev查询: {}:{} v{}", dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion());
            
            ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
            
            if (response.getStatusCode() == HttpStatus.OK) {
                String responseBody = response.getBody();
                if (responseBody != null && !responseBody.trim().equals("{}")) {
                    JsonNode jsonNode = objectMapper.readTree(responseBody);
                    JsonNode vulns = jsonNode.get("vulns");
                    
                    if (vulns != null && vulns.isArray() && vulns.size() > 0) {
                        logger.debug("OSV.dev返回 {} 个漏洞记录", vulns.size());
                        
                        for (JsonNode vuln : vulns) {
                            DependencyRisk risk = parseOSVVulnerability(dependency, vuln);
                            if (risk != null) {
                                risks.add(risk);
                            }
                        }
                    } else {
                        logger.debug("OSV.dev未发现 {}:{} v{} 的漏洞", 
                            dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion());
                    }
                } else {
                    logger.debug("OSV.dev返回空响应，无漏洞数据");
                }
            } else {
                logger.warn("OSV.dev查询失败，HTTP状态码: {}", response.getStatusCode());
            }
        } catch (Exception e) {
            logger.debug("OSV.dev查询异常: {}", e.getMessage());
        }
        
        return risks;
    }
    
    /**
     * 解析OSV.dev漏洞数据 (优化版)
     */
    private DependencyRisk parseOSVVulnerability(DependencyInfo dependency, JsonNode vuln) {
        try {
            Vulnerability vulnerability = new Vulnerability();
            vulnerability.setGroupId(dependency.getGroupId());
            vulnerability.setArtifactId(dependency.getArtifactId());
            
            // 1. 漏洞ID - 优先使用CVE，否则使用OSV ID
            String vulnId = extractVulnerabilityId(vuln);
            vulnerability.setCve(vulnId);
            
            // 2. 漏洞描述 - 合并summary和details
            String description = buildDescription(vuln);
            vulnerability.setDescription(description);
            
            // 3. 严重程度 - 从severity或database_specific中提取
            String severityLevel = extractSeverity(vuln);
            vulnerability.setSeverity(severityLevel);
            
            // 4. 参考链接 - 优先使用ADVISORY类型的链接
            String reference = extractReference(vuln);
            vulnerability.setReference(reference);
            
            // 5. 版本信息 - 解析affected数组获取版本范围和修复版本
            extractVersionInfo(vuln, vulnerability, dependency);
            
            logger.debug("成功解析OSV漏洞: {} ({})", vulnId, severityLevel);
            return new DependencyRisk(dependency, vulnerability);
            
        } catch (Exception e) {
            logger.debug("解析OSV漏洞数据失败: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 提取漏洞ID，优先CVE
     */
    private String extractVulnerabilityId(JsonNode vuln) {
        // 优先从aliases中查找CVE
        JsonNode aliases = vuln.path("aliases");
        if (aliases.isArray()) {
            for (JsonNode alias : aliases) {
                String aliasStr = alias.asText();
                if (aliasStr.startsWith("CVE-")) {
                    return aliasStr;
                }
            }
        }
        
        // 如果没有CVE，使用OSV ID
        return vuln.path("id").asText("UNKNOWN");
    }
    
    /**
     * 构建漏洞描述
     */
    private String buildDescription(JsonNode vuln) {
        String summary = vuln.path("summary").asText("");
        String details = vuln.path("details").asText("");
        
        if (!summary.isEmpty() && !details.isEmpty()) {
            // 如果details比summary长很多，只使用summary
            if (details.length() > summary.length() * 5) {
                return summary;
            }
            // 否则合并两者
            return summary + "\n\n" + details.substring(0, Math.min(details.length(), 500)) + 
                   (details.length() > 500 ? "..." : "");
        }
        
        return !summary.isEmpty() ? summary : 
               (!details.isEmpty() ? details.substring(0, Math.min(details.length(), 300)) : "暂无描述");
    }
    
    /**
     * 提取严重程度
     */
    private String extractSeverity(JsonNode vuln) {
        // 1. 从severity数组中提取
        JsonNode severity = vuln.path("severity");
        if (severity.isArray() && severity.size() > 0) {
            for (JsonNode sev : severity) {
                String type = sev.path("type").asText();
                if ("CVSS_V3".equals(type)) {
                    String score = sev.path("score").asText();
                    return mapCVSSToSeverity(score);
                }
            }
        }
        
        // 2. 从database_specific中提取
        JsonNode dbSpecific = vuln.path("database_specific");
        if (!dbSpecific.isMissingNode()) {
            String severity_str = dbSpecific.path("severity").asText("");
            if (!severity_str.isEmpty()) {
                return mapSeverityString(severity_str);
            }
        }
        
        return "MEDIUM";
    }
    
    /**
     * 从CVSS评分映射到严重程度
     */
    private String mapCVSSToSeverity(String cvssScore) {
        if (cvssScore.isEmpty()) return "MEDIUM";
        
        try {
            // 提取CVSS分数 (格式如 "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H")
            if (cvssScore.contains("/")) {
                String[] parts = cvssScore.split("/");
                for (String part : parts) {
                    if (part.contains(":") && part.split(":").length == 2) {
                        String value = part.split(":")[1];
                        // 根据CVSS组件判断严重程度
                        if ("C:H".equals(part) || "I:H".equals(part) || "A:H".equals(part)) {
                            return "HIGH";
                        }
                    }
                }
            }
            
            // 尝试解析数字分数
            String numPart = cvssScore.replaceAll("[^0-9.]", "");
            if (!numPart.isEmpty()) {
                double score = Double.parseDouble(numPart.split("\\.")[0] + "." + 
                    (numPart.split("\\.").length > 1 ? numPart.split("\\.")[1] : "0"));
                
                if (score >= 9.0) return "CRITICAL";
                if (score >= 7.0) return "HIGH";
                if (score >= 4.0) return "MEDIUM";
                return "LOW";
            }
        } catch (Exception e) {
            logger.debug("解析CVSS评分失败: {}", cvssScore);
        }
        
        return "MEDIUM";
    }
    
    /**
     * 映射严重程度字符串
     */
    private String mapSeverityString(String severity) {
        if (severity == null) return "MEDIUM";
        
        String upper = severity.toUpperCase();
        switch (upper) {
            case "CRITICAL": return "CRITICAL";
            case "HIGH": return "HIGH";
            case "MODERATE": case "MEDIUM": return "MEDIUM";
            case "LOW": return "LOW";
            default: return "MEDIUM";
        }
    }
    
    /**
     * 提取参考链接，优先ADVISORY类型
     */
    private String extractReference(JsonNode vuln) {
        JsonNode references = vuln.path("references");
        if (!references.isArray() || references.size() == 0) {
            return "";
        }
        
        // 优先查找ADVISORY类型的链接
        for (JsonNode ref : references) {
            String type = ref.path("type").asText("");
            if ("ADVISORY".equals(type)) {
                return ref.path("url").asText("");
            }
        }
        
        // 如果没有ADVISORY，使用第一个链接
        return references.get(0).path("url").asText("");
    }
    
    /**
     * 提取版本信息
     */
    private void extractVersionInfo(JsonNode vuln, Vulnerability vulnerability, DependencyInfo dependency) {
        JsonNode affected = vuln.path("affected");
        if (!affected.isArray() || affected.size() == 0) {
            return;
        }
        
        // 查找匹配当前包的affected信息
        for (JsonNode affectedItem : affected) {
            JsonNode packageNode = affectedItem.path("package");
            String packageName = packageNode.path("name").asText("");
            String ecosystem = packageNode.path("ecosystem").asText("");
            
            // 检查是否匹配当前包
            String expectedName = dependency.getGroupId() + ":" + dependency.getArtifactId();
            if ("Maven".equals(ecosystem) && expectedName.equals(packageName)) {
                
                // 提取版本范围
                JsonNode ranges = affectedItem.path("ranges");
                if (ranges.isArray() && ranges.size() > 0) {
                    String versionRange = parseVersionRangeFromOSV(ranges);
                    vulnerability.setVulnerableVersions(versionRange);
                    
                    // 提取修复版本
                    String safeVersion = extractFixedVersionFromRanges(ranges);
                    if (safeVersion != null) {
                        vulnerability.setSafeVersion(safeVersion);
                    }
                }
                
                break; // 找到匹配的包就停止
            }
        }
        
        // 如果没有找到安全版本，设置默认建议
        if (vulnerability.getSafeVersion() == null || vulnerability.getSafeVersion().isEmpty()) {
            vulnerability.setSafeVersion("请查看最新版本");
        }
    }
    
    /**
     * 从OSV ranges中解析版本范围
     */
    private String parseVersionRangeFromOSV(JsonNode ranges) {
        StringBuilder sb = new StringBuilder();
        
        for (JsonNode range : ranges) {
            String type = range.path("type").asText("");
            if ("ECOSYSTEM".equals(type)) {
                JsonNode events = range.path("events");
                if (events.isArray()) {
                    String rangeStr = buildVersionRangeString(events);
                    if (!rangeStr.isEmpty()) {
                        if (sb.length() > 0) sb.append(", ");
                        sb.append(rangeStr);
                    }
                }
            }
        }
        
        return sb.toString();
    }
    
    /**
     * 构建版本范围字符串
     */
    private String buildVersionRangeString(JsonNode events) {
        String introduced = null;
        String fixed = null;
        
        for (JsonNode event : events) {
            if (event.has("introduced")) {
                introduced = event.path("introduced").asText();
            }
            if (event.has("fixed")) {
                fixed = event.path("fixed").asText();
            }
        }
        
        if (introduced != null && fixed != null) {
            if ("0".equals(introduced)) {
                return "< " + fixed;
            } else {
                return ">= " + introduced + ", < " + fixed;
            }
        } else if (introduced != null) {
            return ">= " + introduced;
        } else if (fixed != null) {
            return "< " + fixed;
        }
        
        return "";
    }
    
    /**
     * 从ranges中提取修复版本
     */
    private String extractFixedVersionFromRanges(JsonNode ranges) {
        String latestFixed = null;
        
        for (JsonNode range : ranges) {
            JsonNode events = range.path("events");
            if (events.isArray()) {
                for (JsonNode event : events) {
                    if (event.has("fixed")) {
                        String fixedVersion = event.path("fixed").asText();
                        if (!fixedVersion.isEmpty()) {
                            // 保留最后一个修复版本（通常是最新的）
                            latestFixed = fixedVersion;
                        }
                    }
                }
            }
        }
        
        return latestFixed;
    }
    
    /**
     * 去重复的漏洞
     */
    private List<DependencyRisk> removeDuplicates(List<DependencyRisk> risks) {
        Map<String, DependencyRisk> riskMap = new LinkedHashMap<>();
        
        for (DependencyRisk risk : risks) {
            String key = risk.getGroupId() + ":" + 
                        risk.getArtifactId() + ":" +
                        risk.getCve();
            
            // 保留第一个出现的漏洞
            if (!riskMap.containsKey(key)) {
                riskMap.put(key, risk);
            }
        }
        
        return new ArrayList<>(riskMap.values());
    }

    /**
     * 销毁方法
     */
    public void destroy() {
        if (executorService != null && !executorService.isShutdown()) {
            executorService.shutdown();
            try {
                if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
                    executorService.shutdownNow();
                }
            } catch (InterruptedException e) {
                executorService.shutdownNow();
            }
        }
    }
}